/*
 * 
 */
package com.mperon.util.java;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * The Class ReflectUtils.
 */
public class ReflectUtils {

    /**
     * New instance.
     * 
     * @param clazz
     *            the clazz
     * 
     * @return the t
     */
    public static <T> T newInstance(final Class<T> clazz) {
        T obj = null;
        try {
            if (clazz != null) {
                obj = clazz.newInstance();
            }
        } catch (final InstantiationException e) {
            throw new ReflectException("Was not possible instantiate the class", e);
        } catch (final IllegalAccessException e) {
            throw new ReflectException("Illegal Acess", e);
        }
        return obj;
    }

    /**
     * New instance.
     * 
     * @param className
     *            the class name
     * 
     * @return the t
     */
    @SuppressWarnings("unchecked")
    public static <T> T newInstance(final String className) {
        final Class<?> cls = ReflectUtils.fromName(className);
        T obj = null;
        if (cls != null) {
            obj = (T)ReflectUtils.newInstance(cls);
        }
        return obj;
    }

    public static <T> Constructor<T> findConstructor(final Class<T> clazz, final Class<?>[] types) {
        Constructor<T> out = null;
        try {
            out = clazz.getConstructor(types);
        } catch (SecurityException e) {
            throw new ReflectException("Problems with security", e);
        } catch (NoSuchMethodException e) {
            out = null;
        }
        return out;
    }

    public static <T> Constructor<T> findConstructor(final Class<T> clazz, final Object[] values) {
        final Class<?>[] types = new Class<?>[values.length];
        for (int i = 0; i < values.length; i++) {
            if (values[i] != null) {
                types[i] = values.getClass();
            } else {
                // @LOG invalid value
                types[i] = Object.class;
            }
        }
        return findConstructor(clazz, types);
    }

    /**
     * New instance.
     * 
     * @param clazz
     *            the clazz
     * @param types
     *            the types
     * @param values
     *            the values
     * 
     * @return the t
     */
    public static <T> T newInstance(final Class<T> clazz, final Class<?>[] types,
            final Object[] values) {
        Constructor<T> ct = null;
        T obj = null;
        try {
            if (clazz != null) {
                ct = clazz.getConstructor(types);
                obj = ct.newInstance(values);
            }
        } catch (final InstantiationException e) {
            throw new ReflectException("Was not possible instantiate the class", e);
        } catch (final IllegalAccessException e) {
            throw new ReflectException("Illegal Acess", e);
        } catch (final IllegalArgumentException e) {
            throw new ReflectException("Illegal Argument", e);
        } catch (final InvocationTargetException e) {
            throw new ReflectException("Invocation error", e);
        } catch (final SecurityException e) {
            throw new ReflectException("Problems with security", e);
        } catch (final NoSuchMethodException e) {
            throw new ReflectException("Constructor not found", e);
        }
        /**
         * New instance.
         * 
         * @param className
         *            the class name
         * @param types
         *            the types
         * @param values
         *            the values
         * @return the t
         */
        return obj;
    }

    /**
     * New instance.
     * 
     * @param className
     *            the class name
     * @param types
     *            the types
     * @param values
     *            the values
     * 
     * @return the t
     */
    @SuppressWarnings("unchecked")
    public static <T> T newInstance(final String className, final Class<?>[] types,
            final Object[] values) {
        final Class<?> cls = ReflectUtils.fromName(className);
        T obj = null;
        if (cls != null) {
            obj = (T)ReflectUtils.newInstance(cls, types, values);
        }
        /**
         * From name.
         * 
         * @param name
         *            the name
         * @return the class<?>
         */
        return obj;
    }

    /**
     * From name.
     * 
     * @param name
     *            the name
     * 
     * @return the class<?>
     */
    public static Class<?> fromName(final String name) {
        Class<?> cls = null;
        try {
            cls = Class.forName(name);
        } catch (final LinkageError e) {
            throw new ReflectException("The Linkage process fail: " + name, e);
        } catch (final ClassNotFoundException e) {
            throw new ReflectException("Class not found: " + name, e);
        }
        return cls;
    }

    public static Method findSetterMethod(Class<?> clz, String propertyName) {
        return null;
    }
}
